#include "table.h"

#if defined(GENERIC)
ostream & Table::Print(ostream &os) const
{
	// WRITE THIS
	os << "Generic Table()";
	return os;
}
#endif


/////////////////////////////////////////////////////////////
// 
// Link State
// 
/////////////////////////////////////////////////////////////


#if defined(LINKSTATE)
Table::Table() {}

Table::Table(map<unsigned int, deque<Link *> > outerMap, unsigned int uintNodeID)
{
	m_rTable = outerMap;
	m_uintNodeID = uintNodeID;
}

Table::~Table()
{
	// probably should be some destruction here
}

unsigned int Table::GetNextHopNode(unsigned int dest)
{
	// Link * nextLink = m_rTalbe[dest];
	// return nextLink->dest;
	return 0;
}

double Table::GetNextHopCost(unsigned int dest)
{
	// Link * nextLink = m_rTalbe[dest];
	// return nextLink->lat;

	return 0;
}

Link * Table::GetNextHopLink(unsigned int dest)
{
//	return m_rTalbe[dest];
	return NULL;
}

void Table::SetNextHopLink(unsigned int dest, Link * nextLink)
{
//	m_rTalbe[dest] = nextLink;
}

void Table::SetShortestPath(unsigned dest, deque<Link *> path)
{
	m_rTable[dest] = path;
}


deque<Link *> Table::GetShortestPath(unsigned dest)
{
	return m_rTable[dest];
}

ostream & Table::Print(ostream &os)
{
	map<unsigned, deque<Link *> >::iterator outerIT;

	cout << "----------------------------------------------------------------------" << endl;

	for (outerIT = m_rTable.begin(); outerIT != m_rTable.end(); outerIT++)
	{
		os << "\t\tDestination Node ID: " << (*outerIT).first << endl;
		os << "\t\t\t\tits shortest path: ";
		deque<Link *> path = (*outerIT).second;
		for (deque<Link *>::iterator i = path.begin(); i != path.end(); ++i)
		{
			Link * link = (*i);
			os << " ( " << link->GetSrc() << " -> " << link->GetDest() << " )";
		}

		os << endl;

	}
	cout << "----------------------------------------------------------------------" << endl;
	cout << endl;

	return os;
}

void Table::Print(unsigned int uintNodeID)
{
	map<unsigned, deque<Link *> >::iterator outerIT;

	cout << "----------------------------------------------------------------------" << endl;
	cout << "Routing table for Node " << uintNodeID << endl;


	for (outerIT = m_rTable.begin(); outerIT != m_rTable.end(); outerIT++)
	{
		cout << "\tDestination Node ID: " << (*outerIT).first << endl;
		cout << "\t\tits shortest path: ";
		deque<Link *> path = (*outerIT).second;
		for (deque<Link *>::iterator i = path.begin(); i != path.end(); ++i)
		{
			Link * link = (*i);
			cout << "( " << link->GetSrc() << " -> " << link->GetDest() << " )";
		}
		cout << endl;
	}
	cout << "----------------------------------------------------------------------" << endl;
	cout << endl;
}

void Table::clear()
{
	m_rTable.clear();
}



#endif

/////////////////////////////////////////////////////////////
// 
// Distance Vector
// 
/////////////////////////////////////////////////////////////

#if defined(DISTANCEVECTOR)

Table::Table() {}

Table::Table(map<unsigned int, map<unsigned int, double> > outerMap, unsigned int uintNodeID)
{
	m_rTable = outerMap;
	m_uintNodeID = uintNodeID;
}

Table::~Table()
{
	// probably should be some destruction here
}

ostream & Table::Print(ostream &os)
{
  map<unsigned int, map<unsigned int, double> >::iterator outerIT;
  for (outerIT = m_rTable.begin(); outerIT != m_rTable.end(); outerIT++)
  {
    os << "Node ID: " << (*outerIT).first << endl;
    map<unsigned int, double> inner = (*outerIT).second;
    map<unsigned int, double>::iterator innerIT;
    for (innerIT = inner.begin(); innerIT != inner.end(); innerIT++)
    {
      os << "\t" << "Neighbor ID: " << (*innerIT).first << " => Node Latency: " << (*innerIT).second << endl;
    }

  }
  //os << "Distance Vector Table";
  return os;
}

map<unsigned int, map<unsigned int, double> >::iterator Table::Find(unsigned int uintSource)
{
  return m_rTable.find(uintSource);
}

map<unsigned int, map<unsigned int, double> >::iterator Table::Begin() {return m_rTable.begin();}

map<unsigned int, map<unsigned int, double> >::iterator Table::End() {return m_rTable.end();}

void Table::SetInnerMapValue(map<unsigned int, map<unsigned int, double> >::iterator outerMapIT, map<unsigned int, double> newMap)
{
	// this should swap the current value in the map with the copy of the local parameter, and then once
	// the function exits the local parameter (now holding the old value that was in the map) is discarded
	(*outerMapIT).second.swap(newMap);
}

double Table::GetRoutingCost(unsigned int source, unsigned int dest)
{
	map<unsigned int, double> dest_costs;

	if (m_rTable.find(source) != m_rTable.end())
	{
		dest_costs = m_rTable[source];
	} else {
		return -1;
	}

	if (dest_costs.find(source) != dest_costs.end())
	{
		return dest_costs[dest];
	}

	return -1;
}

void Table::SetRoutingValue(unsigned int source, unsigned int dest, double cost)
{
  map<unsigned int, map<unsigned int, double> >::iterator mapIT = m_rTable.find(source);
  map<unsigned int, double>::iterator innerIT;

  if (mapIT != m_rTable.end())
  {
    innerIT = (*mapIT).second.find(dest);
    if (innerIT != (*mapIT).second.end())
    {
      (*innerIT).second = cost;
    }
   }

  
/*  map<unsigned, double> dest_costs;

  if (m_rTable.find(source) != m_rTable.end())
  {
    dest_costs = m_rTable[source];
  }else{
    return;
  }

  dest_costs[dest] = cost;
  m_rTable[source] = dest_costs;
*/
}

map<unsigned int, double> Table::GetRoutingValueVector(unsigned source)
{
  if (m_rTable.find(source) != m_rTable.end())
  {
    return m_rTable[source];
  }else{
    m_rTable.end();
  }
}

void Table::Print(unsigned int uintNodeID)
{
	map<unsigned int, map<unsigned int, double> >::iterator outerIT;

	cout << "----------------------------------------------------------------------" << endl;
	cout << "Routing table for Node " << uintNodeID << endl;
	for (outerIT = m_rTable.begin(); outerIT != m_rTable.end(); outerIT++)
	{
		cout << "Node ID: " << (*outerIT).first << endl;
		map<unsigned int, double> inner = (*outerIT).second;
		map<unsigned int, double>::iterator innerIT;
		for (innerIT = inner.begin(); innerIT != inner.end(); innerIT++)
		{
			cout << "\t" << "Neighbor ID: " << (*innerIT).first << " => Node Latency: " << (*innerIT).second << endl;
		}

	}
	cout << "----------------------------------------------------------------------" << endl;
	cout << endl;
}

#endif
